/*
 * Copyright (C) 2012 POAS.VSTU
 */

package ui;

import model.CardPile;
import model.Card;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JComponent;


/**
 * Стопка карт как графический элемент. 
 * На самом деле она не имеет своего представления - это участок игровой панели,
 * занятый картами
 */
public class UICardPile {    
    /** Модель стопки, с которой связано данное представление */
    protected CardPile      mModel;
    
    /** Ссылка на панель */
    protected UIGamePanel   mPanel; 
    
    /** Индекс нижнего слоя панели, с  которого будут располагаться карты */
    private int             mZOrderBottom;
    
    /** Координаты стопки */
    private Point           mLocation; 
    
    /** Максимальная длина стопки */
    private int             mMaxWidth;
    
    /** Ориентация */
    private Orientation     mOrientation;
    
    private boolean mIsFaceDown = false;
    
    /**
     * Конструктор.
     * @param cardPlile модель стопки карт.
     */
    public UICardPile(CardPile cardPile, UIGamePanel panel) {
        mModel          = cardPile;   
        mOrientation    = Orientation.NORMAL;
        mLocation       = new Point(0,0);
        mMaxWidth       = 9999;
        mPanel          = panel;
 
        // Создаём карты и отправляем их в контейнер
        for(Card card: mModel)
            mPanel.createUICard(card);
        
        adjustCardsLocation();
    }
    
    /** Изменить максимальную длину стопки */
    public void setMaxWidth(int width) {
        mMaxWidth = width;
        adjustCardsLocation();
    }
    
    /** Ориентация стопки */
    public Orientation getOrientation() {
        return mOrientation;
    }
    
     /** Задать ориентацию стопки */
    public void  setOrientation(Orientation orientation) {
        // Запоминаем локальные координаты всех карт до поворота стопки
        ArrayList<Point> list = new ArrayList<> ();
        for(Card card: mModel)
            list.add(getCardLocation(mPanel.getUICard(card)));
        
        // Меняем ориентацию колоды
        mOrientation = orientation;
        
        // Поворачиваем карты и возвращаем их на своё место
        int i = 0;
        for(Card card: mModel) {
            mPanel.getUICard(card).setOrientation(orientation); 
            setCardLocation(mPanel.getUICard(card), list.get(i));
            i++;
        }
    }

    /** 
     * Повернуть стопку карт.
     * @param steps кол-во поворотов в шагах. Один шаг соответствует повороту на
     * 90 градусов. Положительные значения соответствуют повороту по часовой стрелке,
     * отрицательные - против часовой стрелки.
     */
    public void  rotate(int steps) {
        int nowPos = getOrientation().ordinal();
        for(int i = 0; i < Math.abs(steps); i++) {
            if(steps > 0)
                    nowPos++;
            if(steps < 0)
                    nowPos--;
        
            if(nowPos == 4)
                nowPos = 0;
            if(nowPos == -1)
                nowPos = 3;
        }
        
        setOrientation(Orientation.values()[nowPos]);
        mOrientation = Orientation.values()[nowPos];
    }
    
    /** Позиция */
    public Point getLocation() {
        return mLocation;
    }

    /** Задать позицию */
    public void setLocation(Point p) {
        if(!mModel.isEmpty()) {
            // Вычисляем смещение
            Point dp = new Point(0, 0);
            dp.x = p.x - getLocation().x;
            dp.y = p.y - getLocation().y;
            
            // Меняем позицию каждой карты на текущую + смещение
            for(Card card: mModel) {
                mPanel.getUICard(card).setLocation(mPanel.getUICard(card).getLocation().x + dp.x, 
                        mPanel.getUICard(card).getLocation().y + dp.y);
            }
        }
        
        mLocation = p;
    }
    
    /** Задать позицию */
    public void setLocation(int x, int y) {
        Point p = new Point(x, y);
        setLocation(p);
    }
    
    /** Повернуть стопку лицом вверх. */
    public void turnFaceUp() {
        for(Card card: mModel) {
            mPanel.getUICard(card).turnFaceUp();
        }
        mIsFaceDown = false;
    }
    
    /** Повернуть стопку лицом вниз. */
    public void turnFaceDown() {
        for(Card card: mModel) {
            mPanel.getUICard(card).turnFaceDown();
        }
        mIsFaceDown = true;
    }
    
    /** 
     * Достает заданные карты из стопки, визуализирует этот процесс.
     * @param cards извлекаемые карты
     */
    public void pop(CardPile cards) {
        UICard uiCard;
        for(Card card: cards) {
            uiCard = mPanel.getUICard(card);
            uiCard.actionSetOrientation(Orientation.NORMAL, 100);
        }
    }
    
    /**
     * Подтаскивает карты к стопке, чтобы их можно было поместить в стопку, 
     * визуализирует этот процесс.
     * @param cards перетаскиваемые карты
     */
    public void dragIn(CardPile cards) {
        UICard uiCard;
        for(Card card: cards) {
            uiCard = mPanel.getUICard(card);
            uiCard.actionTurnFaceUp(0);
            uiCard.actionMoveTo(getLocation(), MovementSpeed.NORMAL, 0);
        }
    }
    
    /** 
     * Помещает заданные карты в стопку, визуализирует этот процесс.
     * @param cards добавлемые карты
     */
    public void push(CardPile cards) {
        UICard uiCard;
        for(Card card: cards) {
            uiCard = mPanel.getUICard(card);
            uiCard.actionMoveTo(getLocation(), MovementSpeed.NORMAL, 0);
        }
    }
    
    /** Настроить расположение карт в колоде. */
    protected void adjustCardsLocation() {
    }
	
 /**
     * Перемещает стопку карт в заданную точку с анимацией.
     * @param xx координата x
     * @param yy координата y
     */
    public void moveTo(Point toPoint) throws InterruptedException {
        // Получить все UI карты этой стопки
        ArrayList<UICard> cards = getUICards();
        
        // Для каждой карты осуществить нужное перемещение
        for(UICard card: cards) {
            card.actionMoveTo(toPoint, MovementSpeed.NORMAL, 0);
        }
    }
	
   /** Позиция карты в локальной системе координат стопки */
    public Point getCardLocation(UICard card) { 
        Point p = getLocation();
        
        if(mOrientation == Orientation.NORMAL) {
            p.x = card.getLocation().x - p.x;
            p.y = p.y - card.getLocation().y;
        }
        if(mOrientation == Orientation.ROTATED_CLOCKWISE) {
            p.x = card.getLocation().x - p.x;
            p.y = card.getLocation().y - p.y; 
        }
        if(mOrientation == Orientation.INVERTED) {
            p.x = p.x - card.getLocation().x;
            p.y = card.getLocation().y - p.y;
        }
        if(mOrientation == Orientation.ROTATED_ANTI_CLOCKWISE) {
            p.x = p.x - card.getLocation().x;
            p.y = p.y - card.getLocation().y;
        }
            
        return p;
    }

    /** Задать позицию карты в локальной системе координат стопки */
    public void setCardLocation(UICard card, Point p) {
        // Найдём новую позицию карты в глобальной системе координат
        if(mOrientation == Orientation.NORMAL) {
            p.x = p.x + getLocation().x;
            p.y = getLocation().y + p.y;
        }
        if(mOrientation == Orientation.ROTATED_CLOCKWISE) {
            p.x = p.x + getLocation().x;
            p.y = p.y + getLocation().y; 
        }
        if(mOrientation == Orientation.INVERTED) {
            p.x = getLocation().x + p.x;
            p.y = p.y + getLocation().y;
        }
        if(mOrientation == Orientation.ROTATED_ANTI_CLOCKWISE) {
            p.x = getLocation().x + p.x;
            p.y = getLocation().y + p.y;
        }
        
        // Зададим позицию карты
        card.setLocation(p);
    }
    
    /** Cамый нижний слой для стопки карт */
    public int getZOrderBottom() {
        return mZOrderBottom;
    }
  
    /** Задать самый нижний слой для стопки карт */
    public void setZOrderBottom(int index) {
        mZOrderBottom = index;
    }	
	
   /** z-координата карты внутри стопки (индекс самого верхнего слоя = 0) */
    public int getCardZOrder(UICard card) { 
        return card.getZOrder();
    }

    /** Задать z-координату карты внутри стопки (индекс самого верхнего слоя = 0) */
    public void setCardZOrder(UICard card, int index) {
        card.setZOrder(index);
    }
    
    boolean isFaceDown() {
        return mIsFaceDown;
    }
    
    CardPile getModel() {
        return mModel;
    }
    
    /** Получить представления карт колоды */
    public ArrayList<UICard> getUICards() {
        ArrayList<UICard> uiCards = new ArrayList();
        for(Card card: mModel) {
            uiCards.add(mPanel.getUICard(card));
        }
        return uiCards;
    }
}